package com.hk.Mgr.web.controller.app.yingmi;

import com.alibaba.fastjson.JSON;
import com.hk.api.ProcessAPI;
import com.hk.app.utils.YingmiOpenAPI;
import com.hk.base.BaseCtrl;
import com.hk.commons.ResultCode;
import com.hk.commons.StringHelper;
import com.hk.commons.enm.ShareTypeEnum;
import com.hk.commons.entity.Parameter;
import com.hk.commons.utils.ListPageUtil;
import com.hk.commons.utils.sys.DateHelper;
import com.hk.commons.utils.sys.MapHelper;
import com.hk.commons.vo.JsonResult;
import com.hk.commons.vo.ProductUserRiskLevelResponse;
import com.hk.commons.vo.yingmi.*;
import com.hk.service.order.IParameter;
import com.hk.yingmi.YingmiOpenAPIConstant;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.stream.Collectors;

/**
 * Created by lipei on 2017/8/25.
 * 基金相关的类
 *
 * 01-认申购费率、折扣和预估手续费
 * 02-购买基金
 * 03-设置基金分红方式
 * 04-撤销订单
 * 05-赎回基金
 * 06-获取订单
 * 07-获取在途订单
 * 08-获取仍有效的订单
 * 09-报送基金转换申请
 * 10-取可转换的基金列表接口
 * 11-获取单一订单详情
 * 12-获取订单的总市值、总收益和昨日收益
 * 13-获取下一个交易日
 * 14-获取基金信息接口
 * 15-获取已赎回订单
 * 16-匹配用户风险等级
 */
@Controller
@RequestMapping(value = BaseCtrl.App + "/yingmiAPI/fund")
public class FundCtrl {


    private Logger logger = LoggerFactory.getLogger(this.getClass());


    @Autowired
    private YingmiOpenAPI openAPI;


    @Autowired
    private  FundOrderHelper fundOrderHelper;


    @Autowired
    private FundProductHelper fundProductHelper;

    @Autowired
    private IParameter parmService;

    private static final String ALLOW_YINGMI_RISK_LEVEL_5="ALLOW_YINGMI_RISK_LEVEL_5";
    private static final String YM_FUND_CODE = "YM_FUND_CODE";
    /**
     * 基金每日收益分页大小
     */
    private static final String FUND_DAILY_PAGE_SIZE = "FUND_DAILY_PAGE_SIZE";

    /**
     * 01-认申购费率、折扣和预估手续费
     * @param request
     * @param buyFundFeeReq
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/estimateBuyFundFee", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult estimateBuyFundFee(HttpServletRequest request, @RequestBody BuyFundFeeReq buyFundFeeReq) {

        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("fundCode", buyFundFeeReq.getFundCode());
            validate.check("shareType", buyFundFeeReq.getShareType());

            validate.checkOneOnly("paymentType", "useWallet", buyFundFeeReq.getPaymentType(), buyFundFeeReq.getUseWallet());

            Map<String, String> parMap = MapHelper.beanToMap(buyFundFeeReq);

            if(StringHelper.isEmpty(buyFundFeeReq.getPaymentType())){
                parMap.remove("paymentType");
            }

            if(StringHelper.isEmpty(buyFundFeeReq.getUseWallet())){
                parMap.remove("useWallet");
            }

            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.BUY_FUND_FEE, parMap, null);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }



    /**
     * 02-购买基金
     * @param request
     * @param buyFundReq
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/buy", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult rechargeWallet(HttpServletRequest request, @RequestBody BuyFundReq buyFundReq) {

        ProcessAPI api;

        api = (jsonResult, validate) -> {

            validate.check("brokerUserId", buyFundReq.getBrokerUserId());
            validate.check("accountId", buyFundReq.getAccountId());
            validate.check("brokerOrderNo", buyFundReq.getBrokerOrderNo());
            validate.check("fundCode", buyFundReq.getFundCode());
            validate.check("tradeAmount", buyFundReq.getTradeAmount());
            validate.check("shareType", buyFundReq.getShareType());
            validate.checkOneOnly("paymentMethodId", "walletId", buyFundReq.getPaymentMethodId(), buyFundReq.getWalletId());

            Map<String, String> parMap = MapHelper.transBean2Map(buyFundReq);

            if(StringHelper.isEmpty(buyFundReq.getPaymentMethodId())){
                parMap.remove("paymentMethodId");
            }

            if(StringHelper.isEmpty(buyFundReq.getWalletId())){
                parMap.remove("walletId");
            }

            if(isAllow5()) {
                validate.check("isRiskConfirmAgain", buyFundReq.getIsRiskConfirmAgain());
                validate.check("isRiskConfirmHigh", buyFundReq.getIsRiskConfirmHigh());
                TerminalRequestDTO terminalRequestDTO = new TerminalRequestDTO(request);
                parMap.put("terminalIP", terminalRequestDTO.getTerminalIP());
                parMap.put("terminalType", terminalRequestDTO.getTerminalType());
                parMap.put("terminalInfo", terminalRequestDTO.getTerminalInfo());
            }


            //openAPI.applyTerminalInfo(parMap,new TerminalRequestDTO(request));
            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslPost(YingmiOpenAPIConstant.TRADE_BUYFUND, parMap);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }


    /**
     * 03-设置基金分红方式
     *
     * @param request
     * @param dto
     */
    @ResponseBody
    @RequestMapping(value = YingmiOpenAPIConstant.YINGMI_API_FUND_SET_FUND_DIVIDEND_METHOD, method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult setFundDividendMethod(HttpServletRequest request, @RequestBody SetFundDividendMethodReq dto) {

        ProcessAPI api = (jsonResult, validate) -> {

            validate.check("brokerUserId", dto.getBrokerUserId());
            validate.check("accountId", dto.getAccountId());
            validate.check("brokerOrderNo", dto.getBrokerOrderNo());
            validate.check("shareId", dto.getShareId());
            validate.check("dividendMethod", dto.getDividendMethod());

            Map<String, String> parMap = MapHelper.beanToMap(dto);

            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslPost(YingmiOpenAPIConstant.SET_FUND_DIVIDEND_METHOD, parMap);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult, result);
        };

        return api.process(request);
    }


    /**
     * 04-撤销订单
     * @param request
     * @param dto
     * @return
     */
    @ResponseBody
    @RequestMapping(value ="/cancelFundOrder", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult cancelFundOrder(HttpServletRequest request, @RequestBody CancelFundOrderReq dto) {

        ProcessAPI api = (jsonResult, validate) -> {

            validate.check("brokerUserId", dto.getBrokerUserId());
            validate.check("accountId", dto.getAccountId());
            validate.check("orderId", dto.getOrderId());

            Map<String, String> parMap = MapHelper.beanToMap(dto);
            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslPost(YingmiOpenAPIConstant.CANCEL_ORDER, parMap);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult, result);
        };

        return api.process(request);
    }

    /**
     * 05-赎回基金
     * @param request
     * @param redeemFundReq
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/redeemFund", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult redeemFund(HttpServletRequest request, @RequestBody RedeemFundReq redeemFundReq) {

        ProcessAPI api;

        api = (jsonResult, validate) -> {

            validate.check("brokerUserId", redeemFundReq.getBrokerUserId());
            validate.check("accountId", redeemFundReq.getAccountId());
            validate.check("shareId", redeemFundReq.getShareId());
            validate.check("brokerOrderNo", redeemFundReq.getBrokerOrderNo());
            validate.check("tradeShare", redeemFundReq.getTradeShare());

            Map<String, String> parMap = MapHelper.beanToMap(redeemFundReq);

            if(StringHelper.isEmpty(parMap.get("walletFundCode"))){
                parMap.remove("walletFundCode");
            }

            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslPost(YingmiOpenAPIConstant.TRADE_REDEEMFUND, parMap);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }

    /**
     * 06-获取订单
     * @param request
     * @param req
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFundOrders", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult getFundOrders(HttpServletRequest request, @RequestBody GetFundListReq req) {

        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("brokerUserId", req.getBrokerUserId());
            validate.check("accountId", req.getAccountId());
            validate.check("page", req.getPage());
            validate.check("size", req.getSize());

            Map<String, String> parMap = MapHelper.beanToMap(req);

            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.FUND_ORDERS, parMap, null);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }




    /**
     * 07-获取在途订单
     * @param request
     * @param req
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getProcessingFundOrders", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult getProcessingFundOrders(HttpServletRequest request, @RequestBody GetProcessingFundOrdersReq req) {

        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("brokerUserId", req.getBrokerUserId());
            validate.check("accountId", req.getAccountId());


            Map<String, String> parMap = MapHelper.beanToMap(req);


            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.FUND_PROCESSING_ORDERS, parMap, null);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }



    /**
     * 08-获取仍有效的订单
     * @param request
     * @param req
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFundShares", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult getFundShare(HttpServletRequest request, @RequestBody GetFundShareReq req) {

        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("brokerUserId", req.getBrokerUserId());
            validate.check("accountId", req.getAccountId());

            Map<String, String> parMap = MapHelper.beanToMap(req);

            if(StringHelper.isEmpty(parMap.get("fundCode"))){
                parMap.remove("fundCode");
            }

            String shareId = req.getShareId();

            logger.info("shareId = {}", shareId);

            parMap.remove("shareId");

            String orderListStr = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.FUND_SHARES, parMap, null);

            ArrayList<Map> orderListMap = openAPI.getArrayList(orderListStr);


            if(StringHelper.isNotEmpty(shareId) && openAPI.isJsonArray(orderListStr)){
                Map order  =  orderListMap.stream().filter(map -> map.get("shareId").equals(shareId)).collect(Collectors.toList()).get(0);

                if(order != null){
                    jsonResult.result = order;
                }
            }else{
                jsonResult.result = orderListMap;

                if (orderListMap != null && orderListMap.size() > 0) {
                    openAPI.renderErrorCode(jsonResult,orderListMap.get(0));
                }
            }

        };

        return api.process(request);
    }


    /**
     * 09-报送基金转换申请
     * @param request
     * @param convertFundReq
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/convertFund", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult convertFund(HttpServletRequest request, @RequestBody ConvertFundReq convertFundReq) {

        ProcessAPI api;

        api = (jsonResult, validate) -> {

            validate.check("brokerUserId", convertFundReq.getBrokerUserId());
            validate.check("accountId", convertFundReq.getAccountId());
            validate.check("shareId", convertFundReq.getShareId());
            validate.check("brokerOrderNo", convertFundReq.getBrokerOrderNo());
            validate.check("destFundCode", convertFundReq.getDestFundCode());
            validate.check("destShareType", convertFundReq.getDestShareType());
            validate.check("tradeShare", convertFundReq.getTradeShare());

            Map<String, String> parMap = MapHelper.transBean2Map(convertFundReq);

            if(isAllow5()) {
                validate.check("isRiskConfirmAgain", convertFundReq.getIsRiskConfirmAgain());
                validate.check("isRiskConfirmHigh", convertFundReq.getIsRiskConfirmHigh());
                TerminalRequestDTO terminalRequestDTO = new TerminalRequestDTO(request);
                parMap.put("terminalIP", terminalRequestDTO.getTerminalIP());
                parMap.put("terminalType", terminalRequestDTO.getTerminalType());
                parMap.put("terminalInfo", terminalRequestDTO.getTerminalInfo());
            }

            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslPost(YingmiOpenAPIConstant.TRADE_CONVERTFUND, parMap);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }


    /**
     * 10-取可转换的基金列表接口
     * @param request
     * @param fundCode 要查询的基金代码
     * @param shareType 要查询的收费方式 默认为A前端收费
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getConvertibleFunds", method = RequestMethod.GET)
    public JsonResult getConvertibleFunds(HttpServletRequest request, String fundCode, String shareType) {
        ProcessAPI api = (jsonResult, validate) -> {

            Map<String, String> params = new HashMap<String, String>();
            params.put("fundCode", fundCode);
            params.put("shareType", (shareType == null) ? "A":"A" );

            logger.info("parm Map = {}", params);
            String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GETCONVERTIBLEFUNDS, params, null);
            logger.info("result = {}", jsonResp);

            //模拟数据
            List<HashMap> list = new ArrayList<>();

           com.alibaba.fastjson.JSONArray objects = com.alibaba.fastjson.JSONArray.parseArray(jsonResp);
            for (int i = 0; i < objects.size(); i++) {
                HashMap convertibleFundsResp = new HashMap();
                com.alibaba.fastjson.JSONObject jsonObject = objects.getJSONObject(i);
                convertibleFundsResp.put("fundCode", jsonObject.get("fundCode").toString());
                convertibleFundsResp.put("fundName",jsonObject.get("fundName").toString());
                convertibleFundsResp.put("shareType", jsonObject.get("shareType"));
                //取获取基金等级
                String amacRisk5Level = getAmacRisk5Level(jsonObject.get("fundCode").toString());
                convertibleFundsResp.put("amacRisk5Level",amacRisk5Level);
                list.add(convertibleFundsResp);
            }

            jsonResult.result = list;
            jsonResult.resultCode = ResultCode.SUCC.getCode();
            jsonResult.msg = ResultCode.SUCC.getMsg();
        };

        return api.process(request);
    }

    /**
     * 11 获取单一订单详情
     * @param request
     * @param brokerUserId
     * @param accountId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFundOrder", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    public JsonResult getFundOrders(HttpServletRequest request, @RequestParam String brokerUserId,  @RequestParam String accountId,  @RequestParam String orderId) {

        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("brokerUserId", brokerUserId);
            validate.check("accountId", accountId);
            validate.check("orderId", orderId);


            Map<String, String> parMap = new HashMap<>();
            parMap.put("brokerUserId", brokerUserId);
            parMap.put("accountId", accountId);
            parMap.put("orderId", orderId);


            logger.info("parm Map = {}", parMap);
            String result = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.FUND_ORDER, parMap, null);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };

        return api.process(request);
    }


    /**
     * 12 -获取订单的总市值、总收益和昨日收益
     * @param request
     * @param req
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getSumProfits", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult getSumProfits(HttpServletRequest request, @RequestBody GetSumProfitsReq req) {


        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("brokerUserId", req.getBrokerUserId());
            validate.check("accountId", req.getAccountId());

            Map<String, String> parMap = MapHelper.beanToMap(req);
            parMap.put("isIncludeZeroShare", "1");


            parMap.remove("type");

            String orderListStr = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.FUND_SHARES, parMap, null);


            ArrayList<Map> orderListMap = openAPI.getArrayList(orderListStr);



            //01-1 获取持有订单总市值
            Double totalShareAssetDouble = orderListMap.parallelStream()
                    .filter(n-> n.get("totalShare") != null && n.get("totalShareAsset") != null)
                    .filter(n->(new BigDecimal(n.get("totalShare").toString())).compareTo(new BigDecimal(0)) == 1)
                    .filter(n->StringHelper.isNotEmpty(n.get("totalShareAsset").toString()))
                    .collect(Collectors.summarizingDouble(n -> Double.valueOf(n.get("totalShareAsset").toString()))).getSum();

            BigDecimal totalShareAsset = BigDecimal.valueOf(totalShareAssetDouble);

            //01-2 持有订单昨日收益
            Double previousProfitDouble = orderListMap.parallelStream()
                    .filter(n-> n.get("totalShare") != null && n.get("previousProfit")!= null)
                    .filter(n->(new BigDecimal(n.get("totalShare").toString())).compareTo(new BigDecimal(0)) == 1)
                    .filter(n->StringHelper.isNotEmpty(n.get("previousProfit").toString()))
                    .collect(Collectors.summarizingDouble(n -> Double.valueOf(n.get("previousProfit").toString()))).getSum();
            BigDecimal  previousProfit = BigDecimal.valueOf(previousProfitDouble);


            //01-3 持有订单累计收益
            Double accumulatedProfitDouble = orderListMap.parallelStream()
                    .filter(n-> n.get("totalShare") != null && n.get("accumulatedProfit")!= null)
                    .filter(n->(new BigDecimal(n.get("totalShare").toString())).compareTo(new BigDecimal(0)) == 1)
                    .filter(n->StringHelper.isNotEmpty(n.get("accumulatedProfit").toString()))
                    .collect(Collectors.summarizingDouble(n -> Double.valueOf(n.get("accumulatedProfit").toString()))).getSum();
            BigDecimal  accumulatedProfit = BigDecimal.valueOf(accumulatedProfitDouble);


            //02-1 申购过程中的订单的总金额
            BigDecimal procTradeAmount =  this.getProcSuccessAmount(req);


            //03 已赎回基金总额度
            BigDecimal oldTotalShareAsset = getaOldTotalShareAsset(req);


            //已赎回订单收益
            BigDecimal oldAccumulatedProfit = BigDecimal.valueOf(0.00);


            Map<String, BigDecimal> resultMap = new HashMap<>();
            //总市值
            resultMap.put("totalShareAsset", totalShareAsset);
            //昨日收益
            resultMap.put("previousProfit", previousProfit);
            //总收益
            resultMap.put("accumulatedProfit", accumulatedProfit);

            //申购过程中的订单总金额
            resultMap.put("procTradeAmount", procTradeAmount);


            //已赎回订单的总市值
            resultMap.put("oldTotalShareAsset", oldTotalShareAsset);
            //已赎回订单的总收益
            resultMap.put("oldAccumulatedProfit", oldAccumulatedProfit);



            jsonResult.result = resultMap;
            jsonResult.resultCode = ResultCode.SUCC.getCode();
            jsonResult.msg = ResultCode.SUCC.getMsg();
        };

        return api.process(request);

    }


    /**
     * 13 获取下一个交易日
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getTradeDate", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    public JsonResult getTradeDate(HttpServletRequest request) {
        ProcessAPI api;
        api = (jsonResult, validate) -> {
            Map<String, String> parMap = new HashMap<>();
            parMap.put("offset", "1");

            String result = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.UTILS_GET_TRADEDATE, parMap, null);
            logger.info("result = {}", result);
            openAPI.processJsonResult(jsonResult,result);
        };
        return api.process(request);
    }



    /**
     * 14-获取基金信息接口
     * https://doc.yingmi.cn/pages/viewpage.action?pageId=2064453
     * @param request
     * @param fundCode 指定查询的基金代码
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFundInfo", method = RequestMethod.GET)
    public JsonResult getFundInfo(HttpServletRequest request, String fundCode) {
        ProcessAPI api = (jsonResult, validate) -> {

            Map<String, String> params = new HashMap<String, String>();
            params.put("fundCode", fundCode);

            logger.info("parm Map = {}", params);
            String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.PRODUCT_GETFUNDINFO, params, null);
            logger.info("result = {}", jsonResp);
            openAPI.processJsonResult(jsonResult, jsonResp);
        };

        return api.process(request);
    }

    /**
     * 15-获取已赎回订单
     * @param request
     * @param req
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFundOrdersOld", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult getFundOrdersOld(HttpServletRequest request, @RequestBody GetFundListReq req) {

        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.check("brokerUserId", req.getBrokerUserId());
            validate.check("accountId", req.getAccountId());
            validate.check("page", req.getPage());
            validate.check("size", req.getSize());

            logger.info("parm Map = {}", req.toString());

            List<Map> oldOrderList = this.getOrderOldOrders(req.getBrokerUserId(), req.getAccountId());


            //进行分页
            Integer page = Integer.valueOf(req.getPage());
            Integer size = Integer.valueOf(req.getSize());
            ListPageUtil<Map> listPageUtil = new ListPageUtil<>(oldOrderList, page, size);


            jsonResult.result = listPageUtil.getPagedList();
            jsonResult.resultCode = ResultCode.SUCC.getCode();
            jsonResult.msg = ResultCode.SUCC.getMsg();
        };

        return api.process(request);
    }

    /**
     * 16-匹配用户风险等级
     * @param request
     * @param req
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/checkUserKyc", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public JsonResult checkUserKyc(HttpServletRequest request, @RequestBody CheckUserKycReq req) {
        logger.info("/checkUserKyc" + "\t userId:" + req.getUserId() + "\tfundRiskLevel" + req.getFundRiskLevel());
        ProcessAPI api;
        api = (jsonResult, validate) -> {
            //检查必传
            validate.checkFieldAndPrepare("userId", req.getUserId());
            validate.checkFieldAndPrepare("fundRiskLevel", req.getFundRiskLevel());

            ProductUserRiskLevelResponse matchRuleMap = fundProductHelper.checkUserRiskLevel(req.getFundRiskLevel(), req.getUserId());

            jsonResult.result = matchRuleMap;
            jsonResult.resultCode = ResultCode.SUCC.getCode();
            jsonResult.msg = ResultCode.SUCC.getMsg();
        };

        return api.process(request);
    }


    /**
     * 17-基金的每日收益
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/dailyEarning", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    public JsonResult dailyEarning(HttpServletRequest request,DailyEarningReq req){
        ProcessAPI api = (result, validate) -> {
            validate.check("brokerUserId",req.getBrokerUserId());
            List<Map<String,Object>> list = new ArrayList<>();
            if(StringUtils.isBlank(req.getAccountId())){
                result.result = list;
                return;
            }

            Parameter parameter = parmService.getByName(YM_FUND_CODE);
            //累计
            String sumEarning = getFundEarning(req.getBrokerUserId(),req.getAccountId(),req.getFlag());
            openAPI.processJsonResult(result, sumEarning);
            if(!ResultCode.SUCC.getCode().equals(result.resultCode)){
                return;
            }
            BigDecimal total = sumFundEarning((List<Map<String,Object>>) result.result,parameter);

            //每日
            Parameter pageSizeParameter = parmService.getByName(FUND_DAILY_PAGE_SIZE);
            String dailyEarning = getDailyEarning(req.getBrokerUserId(),req.getAccountId(),req.getFlag(),req.getCurPage(),Integer.valueOf(pageSizeParameter.getValue01()),parameter);
            openAPI.processJsonResult(result, dailyEarning);
            if(!ResultCode.SUCC.getCode().equals(result.resultCode)){
                return;
            }

            List<Map<String,Object>> daily = sumDailyEarning((Map<String,Object>)result.result,parameter);
            Map<String,Object> resultMap = new HashMap<>(2);
            resultMap.put("total",total);
            resultMap.put("daily",daily);
            result.result = resultMap;
        };
        return api.process(request);
    }

    /**
     * 获取所有基金累计收益
     * @param brokerUserId
     * @param accountId
     * @param flag
     * @return
     */
    private String getFundEarning(String brokerUserId,String accountId,String flag){
        Map<String, String> params = new HashMap<>(3);
        params.put("brokerUserId", brokerUserId);
        params.put("accountId", accountId);
        params.put("isIncludeZeroShare","true");

        return openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GET_FUND_SHARES, params, flag);
    }

    /**
     * 计算所有基金收益累计收益
     * @param list
     * @param parameter
     * @return
     */
    private BigDecimal sumFundEarning(List<Map<String,Object>> list,Parameter parameter){
        BigDecimal result = new BigDecimal(0);
        if(list.isEmpty()){
            return result;
        }
        for (Map<String,Object> map:list){
            if(!isYMFundCode(parameter,map.get("fundCode").toString())){
                result = result.add(new BigDecimal(map.get("accumulatedProfit").toString()));
            }

        }
        return result;
    }

    /**
     * 从盈米分页获取基金每日收益
     * @param brokerUserId
     * @param accountId
     * @param flag
     * @param curPage
     * @param pageSize
     * @param parameter
     * @return
     */
    private String getDailyEarning(String brokerUserId, String accountId,String flag, Integer curPage, Integer pageSize,Parameter parameter){
        String result = "{}";
        //查询有数据的最近一天
        Map<String, String> recentlyParams = new HashMap<>(4);
        recentlyParams.put("brokerUserId", brokerUserId);
        recentlyParams.put("accountId", accountId);
        String recentlyResponse = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GET_PROFITS, recentlyParams, flag);
        if(JSON.parseObject(recentlyResponse).isEmpty()){
            return result;
        }

        Date recentlyDate = null;
        Map<String,Object> recentlyMap = JSON.parseObject(recentlyResponse);
        for(Map.Entry<String,Object> entry:recentlyMap.entrySet()){
            //过滤掉华康宝的基金
            if(isYMFundCode(parameter,entry.getKey())){
                continue;
            }
            List<Map<String,Object>> eachFund = (List<Map<String,Object>>)entry.getValue();
            if(recentlyDate == null){
                recentlyDate = DateHelper.stringToDate(eachFund.get(0).get("tradeDate").toString());
            }else {
                Date newDate = DateHelper.stringToDate(eachFund.get(0).get("tradeDate").toString());
                recentlyDate = newDate.after(recentlyDate) ? newDate : recentlyDate;
            }
        }
        if(recentlyDate == null){
            return result;
        }


        Date endDate = DateHelper.addTime(recentlyDate,3,-curPage*pageSize);
        Date beginDate = DateHelper.addTime(endDate,3,-pageSize+1);

        Map<String, String> params = new HashMap<>(4);
        params.put("brokerUserId", brokerUserId);
        params.put("accountId", accountId);
        params.put("beginDate",DateHelper.date2String(beginDate,"yyyy-MM-dd"));
        params.put("endDate",DateHelper.date2String(endDate,"yyyy-MM-dd"));

        result =  openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GET_PROFITS, params, flag);
        return result;
    }

    /**
     * 计算每日收益
     * @param map
     * @param parameter
     * @return
     */
    private List<Map<String,Object>> sumDailyEarning(Map<String,Object> map,Parameter parameter){
        List<Map<String,Object>> result = new ArrayList<>();
        if (map.isEmpty()){
            return result;
        }

        //按日期排序
        Map<String,BigDecimal> sumMap = new TreeMap<>(Comparator.reverseOrder());
        for(Map.Entry<String, Object> entry: map.entrySet()){
            //过滤掉华康宝的基金
            if(isYMFundCode(parameter,entry.getKey())){
                continue;
            }

            List<Map<String,Object>> eachFund = (List<Map<String,Object>>)entry.getValue();
            eachFund.stream()
                    .filter(m -> m.get("isEstimated").equals(false))
                    .forEach(m -> {
                        String tradeDate = m.get("tradeDate").toString();
                        BigDecimal profit = new BigDecimal(m.get("profit").toString());
                        if(sumMap.containsKey(tradeDate)){
                            sumMap.put(tradeDate,sumMap.get(tradeDate).add(profit));
                        }else {
                            sumMap.put(tradeDate,profit);
                        }
                    });
        }

        //map重装成list返回给前端
        for(Map.Entry<String,BigDecimal> entry : sumMap.entrySet()){
            Map<String,Object> dailyEarning = new HashMap<>(2);
            dailyEarning.put("tradeDate",entry.getKey());
            dailyEarning.put("profit",entry.getValue());
            result.add(dailyEarning);
        }

        return result;
    }

    /**
     * 是否是华康宝的基金
     * @param fundCode
     * @return
     */
    private Boolean isYMFundCode(Parameter parameter,String fundCode){
        if(parameter == null){
            return false;
        }
        if(parameter.getValue01().indexOf(fundCode) >= 0){
            return true;
        }
        return false;
    }

    /**
     * 获取已赎回的订单
     * @param brokerUserId
     * @param accountId
     * @return
     */
    public List<Map> getOrderOldOrders(String brokerUserId, String accountId){

        List<Map> orldOrderListMap024 = getTotalOrdersByFundOrderCode(brokerUserId, accountId, "024");

        List<Map> orldOrderListMapw05 = getTotalOrdersByFundOrderCode(brokerUserId, accountId, "W05");

        //合并两种订单
        orldOrderListMap024.addAll(orldOrderListMapw05);


        orldOrderListMap024.parallelStream().sorted((n1, n2) -> n1.get("orderCreatedOn").toString().compareTo(n1.get("orderCreatedOn").toString()))
                .collect(Collectors.toList());

        return  orldOrderListMap024;

    }

    /**
     * 前端特殊转换方法
     * A:前端收费
     * B：后端收费
     * C: C端收费
     * @param json
     * @return
     * @throws IOException
     */
    private  void processJsonTranResult(JsonResult jsonResult, String json) throws IOException {
        if (StringUtils.isBlank(json))
            return;

        if (openAPI.isJsonArray(json)) {
            ArrayList result = this.convertArrayTranToList(json);

            jsonResult.result = result;
            return;
        }

        HashMap map = openAPI.convertToMap(json);
        jsonResult.result = map;

        if (map.get("code") != null && map.get("msg") != null) {
            jsonResult.resultCode = map.get("code").toString();
            jsonResult.msg = map.get("msg").toString();
        }
    }

    /**
     * 前端特殊转换
     * A:前端收费
     * B：后端收费
     * C: C端收费
     * @param json
     * @return
     * @throws IOException
     */
    private ArrayList convertArrayTranToList(String json) throws IOException {
        JSONArray jsonArray = new JSONArray(json);
        ArrayList result = new ArrayList();

        for (Object one : jsonArray) {
            JSONObject jsonpObject = (JSONObject)one;
            Map oneMap = openAPI.convertToMap(jsonpObject.toString());

            oneMap.put("shareTypeStr", ShareTypeEnum.getMsgByCode(oneMap.get("shareType").toString()));

            result.add(oneMap);
        }

        return result;
    }

    /**
     * 获取申购过程中的订单总市值
     * @param req
     * @return
     */
    private BigDecimal getProcSuccessAmount( GetSumProfitsReq req){
        try {

            Map<String, String> parMap = MapHelper.beanToMap(req);

            String procOrderResult = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.FUND_PROCESSING_ORDERS, parMap, null);


            ArrayList<Map> procOrderListMap = openAPI.getArrayList(procOrderResult);

            Double procTradeAmountDouble = procOrderListMap.parallelStream()
                    .filter(n-> n.get("tradeAmount") != null)
                    .filter(n->StringHelper.isNotEmpty(n.get("tradeAmount").toString()))
                    .collect(Collectors.summarizingDouble(n -> Double.valueOf(n.get("tradeAmount").toString()))).getSum();

            return BigDecimal.valueOf(procTradeAmountDouble);
        } catch (Exception e) {
            logger.error("getProcTradeAmount error" + e);

            return BigDecimal.valueOf(0.00);
        }


    }


    /**
     * 获取已赎回订单的投资资产
     * @param req
     * @return
     */
    private BigDecimal  getaOldTotalShareAsset(@RequestBody GetSumProfitsReq req) {

        List<Map> orldOrderList = this.getOrderOldOrders(req.getBrokerUserId(), req.getAccountId());

        //获取已赎回基金总市值
        Double amount =  orldOrderList.parallelStream()
                .filter(n-> StringHelper.isNotEmpty(n.get("successAmount").toString()))
                .collect(Collectors.summarizingDouble(n -> Double.valueOf(n.get("successAmount").toString()))).getSum();

        return   BigDecimal.valueOf(amount);
    }







    /**
     * 根据fundOrderCode 获取用户该类型总的订单
     * @param brokerUserId
     * @param accountId
     * @param fundOrderCode
     * @return
     */
    public List<Map> getTotalOrdersByFundOrderCode(String brokerUserId, String accountId, String fundOrderCode){

        int curPage = 0;

        List<Map> orderListMap = getTotalOrderByPage(brokerUserId, accountId, fundOrderCode, 0);
        int totalSzie = orderListMap.size();

        while(totalSzie == (curPage + 1) * 50){
            curPage += 5;
            orderListMap.addAll( getTotalOrderByPage(brokerUserId, accountId, fundOrderCode, curPage));
            totalSzie = orderListMap.size();
        }

        return  orderListMap;
    }

    /**
     * 同时开启5个线程进行查询
     * @param brokerUserId
     * @param accountId
     * @param fundOrderCode
     * @param page
     * @return
     */
    public List<Map> getTotalOrderByPage(String brokerUserId, String accountId, String fundOrderCode, int page){

        List<Map> orderListMap = new ArrayList<>();
        fundOrderHelper.setBrokerUserId(brokerUserId);
        fundOrderHelper.setAccountId(accountId);
        fundOrderHelper.setFundOrderCode(fundOrderCode);
        fundOrderHelper.setCurPage(0);

        logger.info("will start the thread");

        Callable<List<Map>> fundOrderCallable01 = fundOrderHelper;
        FutureTask<List<Map>> getFundOrderTask01 = new FutureTask<>(fundOrderCallable01);
        new Thread(getFundOrderTask01).start();

        Callable<List<Map>> fundOrderCallable02 = fundOrderHelper;
        FutureTask<List<Map>> getFundOrderTask02 = new FutureTask<>(fundOrderCallable02);
        new Thread(getFundOrderTask02).start();

        Callable<List<Map>> fundOrderCallable03 = fundOrderHelper;
        FutureTask<List<Map>> getFundOrderTask03 = new FutureTask<>(fundOrderCallable03);
        new Thread(getFundOrderTask03).start();


        Callable<List<Map>> fundOrderCallable04 = fundOrderHelper;
        FutureTask<List<Map>> getFundOrderTask04 = new FutureTask<>(fundOrderCallable04);
        new Thread(getFundOrderTask04).start();

        Callable<List<Map>> fundOrderCallable05 = fundOrderHelper;
        FutureTask<List<Map>> getFundOrderTask05 = new FutureTask<>(fundOrderCallable05);
        new Thread(getFundOrderTask05).start();

        try{
            List<Map> orderListMap01 = getFundOrderTask01.get();
            List<Map> orderListMap02 = getFundOrderTask02.get();
            List<Map> orderListMap03 = getFundOrderTask03.get();
            List<Map> orderListMap04 = getFundOrderTask04.get();
            List<Map> orderListMap05 = getFundOrderTask05.get();

            if( orderListMap01 != null){
                orderListMap.addAll(orderListMap01);
            }

            if( orderListMap02 != null){
                orderListMap.addAll(orderListMap02);
            }

            if( orderListMap03 != null){
                orderListMap.addAll(orderListMap03);
            }

            if( orderListMap04 != null){
                orderListMap.addAll(orderListMap04);
            }

            if( orderListMap05 != null){
                orderListMap.addAll(orderListMap05);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return  orderListMap;
    }

    /**
     * 获取基金风险等级
     * @param fundCode 基金码
     * @return 基金风险等级值
     */
    private String getAmacRisk5Level(String fundCode) {
        logger.info("获取基金风险等级: url /getConvertibleFunds");
        Map<String, String> params = new HashMap<String, String>();
        params.put("fundCode", fundCode);

        logger.info("parm Map = {}", params);
        String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.PRODUCT_GET_FUND_INFO, params, null);
        logger.info("result = {}", jsonResp);
        String amacRisk5Level="";
        if(!StringUtils.isBlank(jsonResp)) {
            JSONObject jsonObject = new JSONObject(jsonResp);
            amacRisk5Level = jsonObject.get("amacRisk5Level").toString();
        }
        return amacRisk5Level;
    }

    /**
     * 可转换的基金测试json string
     * @return
     */
    private String getConvertibleFunds() {
        return  "[\n" +
                "        {\n" +
                "            \"fundCode\": \"270001\",\n" +
                "            \"fundName\": \"广发聚富\",\n" +
                "            \"shareType\": [\n" +
                "                \"A\"\n" +
                "            ]\n" +
                "        },\n" +
                "        {\n" +
                "            \"fundCode\": \"270004\",\n" +
                "            \"fundName\": \"广发货币A\",\n" +
                "            \"shareType\": [\n" +
                "                \"A\"\n" +
                "            ]\n" +
                "        },\n" +
                "        {\n" +
                "            \"fundCode\": \"002295\",\n" +
                "            \"fundName\": \"广发稳安保本\",\n" +
                "            \"shareType\": [\n" +
                "                \"A\"\n" +
                "            ]\n" +
                "        },\n" +
                "        {\n" +
                "            \"fundCode\": \"000509\",\n" +
                "            \"fundName\": \"广发钱袋子货币\",\n" +
                "            \"shareType\": [\n" +
                "                \"A\"\n" +
                "            ]\n" +
                "        }\n" +
                "    ]";
    }

    //ALLOW_YINGMI_RISKLEVEL

    /**
     * 是否启用销售适当性 1:启用 0：不启用
     * @return
     */
    private Boolean isAllow5() {
        Parameter byName = parmService.getByName(ALLOW_YINGMI_RISK_LEVEL_5);
        if(null == byName) {
            return  false;
        }
        String byNameValue = byName.getValue01();
        if("1".equals(byNameValue)) {
            return true;
        }
        return false;
    }
}
